package ru.amse.tsyganov.jumleditor.commands;

import java.util.LinkedList;
import java.util.ListIterator;

public class ViewsManager {
	private final LinkedList<Command> commands = 
		new LinkedList<Command>();
	private final int maxSize;
	private Command lastExecutedCommand;
	
	public ViewsManager() {
		maxSize = 0;
	}
	
	public ViewsManager(int maxSize) {
		if (maxSize < 0) {
			throw new IllegalArgumentException();
		}
		this.maxSize = maxSize;
	}
	
	public void executeCommand(Command command) {
		if (command == null) {
			throw new IllegalArgumentException();
		}
		putCommandToList(command);
		command.execute();
		lastExecutedCommand = command;
	}
	
	public boolean rollback() {
		assert lastExecutedCommand == null || 
			commands.contains(lastExecutedCommand);
		
		if (lastExecutedCommand == null) {
			return false;
		}
		lastExecutedCommand.unexecute();
		for (ListIterator<Command> i = commands.listIterator(commands.size()); 
			i.hasPrevious(); ) {
			
			Command c = i.previous();
			if (lastExecutedCommand == c) {
				if (i.hasPrevious()) {
					lastExecutedCommand = i.previous();
				} else {
					lastExecutedCommand = null;
				}
				break;
			}
		}
		
		assert lastExecutedCommand == null || 
			commands.contains(lastExecutedCommand);
		
		return true;
	}
	
	public boolean redo() {
		assert lastExecutedCommand == null || 
			commands.contains(lastExecutedCommand);
		
		if (lastExecutedCommand == commands.getLast() ||
				commands.size() == 0) {
			return false;
		}
		
		if (lastExecutedCommand == null) {
			assert commands.size() > 0;
			lastExecutedCommand = commands.getFirst();
			lastExecutedCommand.execute();
			return true;
		}
		
		for (ListIterator<Command> i = commands.listIterator(); 
			i.hasNext();) {

			Command c = i.next();
			if (lastExecutedCommand == c) {
				
				assert lastExecutedCommand != commands.getLast();
				
				lastExecutedCommand = i.next();
				lastExecutedCommand.execute();
				
				break;
			}
		}
  		
		assert lastExecutedCommand == null || 
			commands.contains(lastExecutedCommand);
	
		return true;
	}
	
	private void putCommandToList(Command command) {
		assert command != null;
		
		for (ListIterator<Command> i = commands.listIterator(commands.size()); 
			i.hasPrevious(); ) {
			
			Command c = i.previous();
			if (lastExecutedCommand == c) {
				break;
			}
			i.remove();
		}
		commands.addLast(command);
		if ((maxSize != 0) && (commands.size() > maxSize)) {
			commands.removeFirst();
		}
		
		assert maxSize == 0 || commands.size() <= maxSize;
		assert commands.contains(command);
	}
}
